/*-------------------------------------------------------------------------
 *
 * spgproc.c
 *	  SP-GiST 操作类的公共支持程序。
 *
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * IDENTIFICATION
 *			src/backend/access/spgist/spgproc.c
 *
 *-------------------------------------------------------------------------
 */

#include "postgres.h"

#include <math.h>

#include "access/spgist_private.h"
#include "utils/builtins.h"
#include "utils/float.h"
#include "utils/geo_decls.h"

#define point_point_distance(p1,p2) \
	DatumGetFloat8(DirectFunctionCall2(point_distance, \
									   PointPGetDatum(p1), PointPGetDatum(p2)))

/* 假设盒子按轴对齐的点-盒距离 */
static double fc_point_box_distance(Point *fc_point, BOX *fc_box)
{
	double		fc_dx,
				fc_dy;

	if (isnan(fc_point->x) || isnan(fc_box->low.x) ||
		isnan(fc_point->y) || isnan(fc_box->low.y))
		return get_float8_nan();

	if (fc_point->x < fc_box->low.x)
		fc_dx = fc_box->low.x - fc_point->x;
	else if (fc_point->x > fc_box->high.x)
		fc_dx = fc_point->x - fc_box->high.x;
	else
		fc_dx = 0.0;

	if (fc_point->y < fc_box->low.y)
		fc_dy = fc_box->low.y - fc_point->y;
	else if (fc_point->y > fc_box->high.y)
		fc_dy = fc_point->y - fc_box->high.y;
	else
		fc_dy = 0.0;

	return HYPOT(fc_dx, fc_dy);
}

/*
 * 返回给定键到排序扫描键数组的距离。预期叶键为点，非叶键为盒子。扫描键参数预期为点。
 */
double *
spg_key_orderbys_distances(Datum fc_key, bool fc_isLeaf,
						   ScanKey fc_orderbys, int fc_norderbys)
{
	int			fc_sk_num;
	double	   *fc_distances = (double *) palloc(fc_norderbys * sizeof(double)),
			   *fc_distance = fc_distances;

	for (fc_sk_num = 0; fc_sk_num < fc_norderbys; ++fc_sk_num, ++fc_orderbys, ++fc_distance)
	{
		Point	   *fc_point = DatumGetPointP(fc_orderbys->sk_argument);

		*fc_distance = fc_isLeaf ? point_point_distance(fc_point, DatumGetPointP(fc_key))
			: fc_point_box_distance(fc_point, DatumGetBoxP(fc_key));
	}

	return fc_distances;
}

BOX *
box_copy(BOX *fc_orig)
{
	BOX		   *fc_result = palloc(sizeof(BOX));

	*fc_result = *fc_orig;
	return fc_result;
}
